﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using VsxFactory.Modeling.VisualStudio;
using Microsoft.VisualStudio.Modeling;
using System.IO;
using Microsoft.VisualStudio.TextTemplating;
using System.Resources;
using VsxFactory.Modeling.Repository;
using VsxFactory.Modeling.Strategies.Rules;

namespace VsxFactory.Modeling.Strategies.Generators
{
    public class T4Generator : INodeGenerator
    {
        private string templateContent;
        private Encoding encoding;
        private T4Engine engine;
        public string TemplateFileName { get; set; }
        private ResourceManager resourceManager;

        public T4Generator() {
        }

        public T4Generator(string templateFileName, ResourceManager resourceManager = null) {
            this.TemplateFileName = templateFileName;
            this.resourceManager = resourceManager;
        }

        private ResourceManager ResourceManager {
            get {
                return resourceManager;
            }
        }

        public virtual void Initialize(IStrategyContext context) {
            IServiceProvider serviceProvider = context.ServiceProvider;
            engine = new T4Engine(serviceProvider);

            var templateFullName = Path.Combine(this.GetType().Assembly.Location, TemplateFileName);
            if (!File.Exists(templateFullName)) {
                templateFullName = Path.Combine(context.Settings.GetPackageFolder(PackageKind.T4Template), TemplateFileName);
            }

            // Recherche en tant que fichier
            if (File.Exists(templateFullName)) {
                templateContent = File.ReadAllText(templateFullName);
                encoding = EncodingHelper.GetEncoding(templateFullName);
            }
            else if (ResourceManager != null) {
                // Sinon recherche dans les ressources
                try {
                    using (StreamReader ms = new StreamReader(new MemoryStream((byte[])ResourceManager.GetObject(Path.GetFileNameWithoutExtension(templateFullName))))) {
                        templateContent = ms.ReadToEnd();
                    }
                }
                catch {
                    // throw new StrategyException(String.Format("Template file {0} not found", TemplateFile));
                }
            }

            if (templateContent == null) {
                throw new StrategyException(String.Format("Template file {0} not found", TemplateFileName));
            }
        }

        protected virtual string PrepareTemplateContent(IStrategyContext context, GenerationSpec element) {
            var s = templateContent.Replace("{ModelFileName}", context.ModelFileName);
            return templateContent.Replace("$edmxInputFile$", context.ModelFileName);
        }

        public bool Generate(IStrategyContext ctx, ref string outputFileName, GenerationSpec element, string @namespace) {
            T4Session session = new T4Session();
            session.Namespace = @namespace;
            session.OutputFileName = outputFileName;
            session.Encoding = encoding;
            session.TemplateContent = PrepareTemplateContent(ctx, element);
            session.ModelFileName = Path.GetFileName(outputFileName);
            if (element != null)
                session.CurrentElement = element.ModelElement;
            session.TemplateFileName = TemplateFileName;
            var result = engine.RunTemplate(session);
            outputFileName = session.OutputFileName;
            return result;
        }

        IVsProjectFileItem INodeGenerator.AddToSolution(IVsProject projectNode, IVsProjectFileItem node, string fullName) {
            if (node != null) {
                node.AddFromFile(fullName);
            }
            else {
                string relativeFileName = Utils.PathRelativePathToFolder(projectNode.Path, fullName);
                node = projectNode.AddItem(relativeFileName);
            }
            return node;
        }
    }
}
